package world.ztomorrow.push.utils;

import com.github.benmanes.caffeine.cache.Cache;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;


@Component
@RequiredArgsConstructor
public class CacheUtils {

    private final Cache<String, List<Object>> caffeine;
    private  final  Cache<String, Object> caffeineOne;
    private final StringRedisTemplate stringRedisTemplate;

    public <T> List<T> getCache(Function<Object, T> Function,
                                String localKey, String redisKey,
                                Function<String, T> fromStringFunction) {
        // 先从本地缓存取
        List<Object> localCache = caffeine.getIfPresent(localKey);
        // 命中返回，并刷新过期时间
        if (localCache != null && !localCache.isEmpty()) {
            return localCache.stream().map(Function).collect(Collectors.toList());
        }
        // 未命中，从redis中获取数据
        List<String> redisCache = stringRedisTemplate.opsForList().range(redisKey, 0, -1);
        // 命中返回，并刷新过期时间
        if (redisCache != null && !redisCache.isEmpty()) {
            return redisCache.stream().map(fromStringFunction).toList();
        }
        return null;
    }


    public <T> void saveCache(
            List<T> obj,
            String localKey,
            String redisKey,
            long expireTime,
            Function<T, String> toStringFunction
    ) {
        // 将对象列表转换为 Object 列表
        List<Object> resultList = new ArrayList<>(obj);
        caffeine.put(localKey, resultList);

        // 将对象列表转换为字符串列表
        List<String> stringList = obj.stream()
                .map(toStringFunction)
                .collect(Collectors.toList());
        stringRedisTemplate.opsForList().rightPushAll(redisKey, stringList);
        stringRedisTemplate.expire(redisKey, expireTime, TimeUnit.MINUTES);
    }

    public <T> T getCacheOne(Function<Object, T> Function,
                             String localKey, String redisKey,
                             Function<String, T> fromStringFunction){
        // 先从本地缓存取
        Object localCache = caffeineOne.getIfPresent(localKey);
        // 命中返回，并刷新过期时间
        if (localCache != null) {
            return Function.apply(localCache);
        }
        // 未命中，从redis中获取数据
        String RedisCache = stringRedisTemplate.opsForValue().get(redisKey);
        // 命中返回，并刷新过期时间
        if (RedisCache != null && !RedisCache.isEmpty()) {
            return fromStringFunction.apply(RedisCache);
        }
        return null;
    }


    public <T> void saveCacheOne( T obj, String localKey, String redisKey,
                                  long expireTime, Function<Object, String> fromStringFunction){
        caffeineOne.put(localKey, obj);
        stringRedisTemplate.opsForValue().set(redisKey, fromStringFunction.apply(obj),
                expireTime, TimeUnit.MINUTES);
    }

    public void clearCache(String localKey, String redisKey) {
        caffeineOne.invalidate(localKey);
        stringRedisTemplate.delete(redisKey);
    }
}
